#include "stdafx.h"

#include "HttpConfig.h"
#include "http.h"

#include <pugixml\pugixml.hpp>
#include "wxtl\StringUtil.h"
#include "wxtl/Path.h"

HttpConfig::HttpConfig(void)
	:m_mimeTableSize(0)
	,m_root(NULL)
	,m_locations(0)
{
	Clear();
}


HttpConfig::~HttpConfig(void)
{
}

void HttpConfig::Clear(void)
{
	m_locations = 0;
	m_performance = Performance();
	if(m_mimeTableSize)
	{
		for(size_t i = 0; i < m_mimeTableSize; ++i)
		{
			http_free(m_mimeTable[i][0]);
			http_free(m_mimeTable[i][1]);
		}
		m_mimeTableSize = 0;
	}
	memset(m_mimeTable, 0, sizeof(m_mimeTable));

	m_port = 80;

	if(m_root)
	{
		http_free(m_root);
	}

	std::wstring curdir = wxtl::getModuleDir();
	m_root = http_strdup(wxtl::unicodeToAscii(curdir.c_str()).c_str());
}

bool HttpConfig::ReadConfig(const _TCHAR* filename)
{
	Clear();
	HTTPINFO("Parsing config file " << filename);
	pugi::xml_document document;
	pugi::xml_parse_result result = document.load_file(filename);
	if(!result)
	{
		
		HTTPERROR("Error reading config file: " << filename << " " << result.description());
		return false;
	}
	pugi::xml_node config = document.child("http");
	if(!config)
	{
		HTTPERROR("Missing <http> in config file: " << filename);	
		return false;
	}

	for(pugi::xml_node current = config.first_child(); 
		current; 
		current = current.next_sibling())
	{
		if(strcmp(current.name(), "MimeTypes") == 0)
		{
			if(!ReadMimeTypes(&current))
			{
				HTTPERROR("Error reading mime types from " << filename);
				return false;
			}
		}
		else if(strcmp(current.name(), "Performance") == 0)
		{
			if(!ReadPerformance(&current))
			{
				HTTPERROR("Error reading Performance data from " << filename);
				return false;
			}
		}
		else if(strcmp(current.name(), "Server") == 0)
		{
			if(!ReadServer(&current))
			{
				HTTPERROR("Error reading server parameters data from " << filename);
				return false;
			}
		}
		else if(strcmp(current.name(), "Location") == 0)
		{
			if(!ReadLocation(&current))
			{
				HTTPERROR("Error reading server parameters data from " << filename);
				return false;
			}
		}
		else if(strcmp(current.name(), "Proxy") == 0)
		{
			if(!ReadProxy(&current))
			{
				HTTPERROR("Error reading server parameters data from " << filename);
				return false;
			}
		}
		else
		{
			HTTPWARN("Unexpected <" << current.name() << "> while parsing config from " << filename);
		}
	}

	return true;
}

bool  HttpConfig::ReadMimeTypes(const pugi::xml_node* node)
{
	size_t currentType = 0;

	for(pugi::xml_node current = node->first_child(); 
		current; 
		current = current.next_sibling())
	{
		if(strcmp(current.name(), "MimeType") != 0)
		{
			HTTPWARN("Unexpected " << current.name() << " while parsing MimeTypes");
			continue;
		}

		const char* ext =  current.attribute("extension").value();
		const char* type =  current.attribute("type").value();
		if(!ext || !strlen(ext))
		{
			HTTPWARN("No extension attribute in <MimeType>");
			continue;
		}

		if(!type || !strlen(type))
		{
			HTTPWARN("No type attribute in <MimeType>");
			continue;
		}

		m_mimeTable[currentType][0] = http_strdup(ext);
		m_mimeTable[currentType][1] = http_strdup(type);

		currentType++;
	}

	if(currentType == 0)
	{
		HTTPWARN("<MimeTypes> holds no types");
		return false;
	}

	m_mimeTableSize = currentType;

	return true;
}

bool HttpConfig::ReadPerformance( const pugi::xml_node* node )
{
	auto var = node->child("MaxIocpThreads").attribute("value");
	if(var)
	{
		if(!var.as_uint())
		{
			HTTPERROR("Invalid MaxIocpThreads parameter value");
			return false;
		}
		else
		{
			m_performance.iocpHandlers = var.as_uint();
		}		
	}

	return true;
}

bool HttpConfig::ReadServer( const pugi::xml_node* node )
{
	auto var = node->child("port").attribute("value");
	if(var)
	{
		if(!var.as_uint())
		{
			HTTPERROR("Invalid port parameter value");
			return false;
		}
		else
		{
			m_port = (WORD)var.as_uint();
		}		
	}
	return true;
}

bool HttpConfig::ReadProxy( pugi::xml_node* node )
{
	m_locations++;

	CurrentLocation()->isProxy = true;

	auto var = node->child("Relay").attribute("value");
	if(var)
	{
		if(!var.value())
		{
			HTTPERROR("Invalid relay");
			return false;
		}
		else
		{
			CurrentLocation()->m_root = http_strdup(var.value());
		}		
	}
	else
	{
		HTTPERROR("Relay node is required in Proxy");
		return false;
	}

	var = node->child("Uri").attribute("value");
	if(var)
	{
		if(!var.value())
		{
			HTTPERROR("Invalid Uri");
			return false;
		}
		else
		{
			CurrentLocation()->m_url = http_strdup(var.value());
		}		
	}
	else
	{
		HTTPERROR("Uri node is required in Proxy");
		return false;
	}

	var = node->child("Hostname").attribute("value");
	if(var)
	{
		if(!var.value())
		{
			HTTPERROR("Invalid Hostname in Proxy");
			return false;
		}
		else
		{
			CurrentLocation()->host = http_strdup(var.value());
		}		
	}

	return true;
}

bool HttpConfig::ReadLocation( pugi::xml_node* node )
{
	m_locations++;

	CurrentLocation()->isProxy = false;

	auto var = node->child("Root").attribute("value");
	if(var)
	{
		if(!var.value())
		{
			HTTPERROR("Invalid root");
			return false;
		}
		else
		{
			m_location[m_locations-1].m_root = http_strdup(var.value());
		}		
	}
	else
	{
		HTTPERROR("Root node is required in Location");
		return false;
	}

	var = node->child("Uri").attribute("value");
	if(var)
	{
		if(!var.value())
		{
			HTTPERROR("Invalid Uri");
			return false;
		}
		else
		{
			m_location[m_locations -1].m_url = http_strdup(var.value());
		}		
	}
	else
	{
		HTTPERROR("Uri node is required in Location");
		return false;
	}

	return true;
}

HttpLocationConfig * HttpConfig::CurrentLocation()
{
	return &m_location[m_locations-1];
}
